#include "StdAfx.h"
#include "csvCalculations.h"


csvCalculations::csvCalculations(void)
{
}

//loops through a folder calculating the average for each file, includes all files
hash_map<string, double> csvCalculations::CalculateAveragesForFolder(string folder, string column)
{
	hash_map<string, double> results;

	stringstream ss;
	ss << folder << "\\";
	folder = ss.str();

	list<string> files = GetFiles(folder);

	for(list<string>::iterator it = files.begin(); it!=files.end(); it++)
	{
		stringstream ssf;
		string file = *it;
		ssf << folder << file;
		double result = 0.0;

		results[file] = AverageForFile(ssf.str(), column);
	}


	return results;
}

//loops through a folder calculating the average for each so long as the values fall within a given range
hash_map<string, double> csvCalculations::CalculateAveragesForFolder(string folder, string column, double min, double max)
{
	hash_map<string, double> results;

	stringstream ss;
	ss << folder << "\\";
	folder = ss.str();

	list<string> files = GetFiles(folder);
	
	for(list<string>::iterator it = files.begin(); it!=files.end(); it++)
	{
		stringstream ssf;
		string file = *it;
		ssf << folder << file;
		double result = 0.0;

		results[file] = AverageForFile(ssf.str(), column, min, max);
	}


	return results;
}

//calculates the average for a given file within a range
double csvCalculations::AverageForFile(string file, string colHeader)
{
	list<double> data = GetData(FileToRows(file), colHeader);
	
	double total = 0;
	int count = 0;
	for(list<double>::iterator it = data.begin(); it != data.end(); it++)
	{
		double tempD = *it;
		total += tempD;
		count ++;
	}

	if(count > 0)
	{
		return (total / count);
	}
	else
	{
		return 0;
	}	
}

//calculates the average for a given file within a range
double csvCalculations::AverageForFile(string file, string colHeader, double minVal, double maxVal)
{
	list<double> data = GetData(FileToRows(file), colHeader);

	double total = 0;
	int count = 0;
	for(list<double>::iterator it = data.begin(); it != data.end(); it++)
	{
		double tempD = *it;

		if((tempD > minVal) && (tempD < maxVal))
		{
			total += tempD;
			count ++;
		}		
	}

	if(count > 0)
	{
		return (total / count);
	}
	else
	{
		return 0;
	}
}

//converts a file to rows
list<string> csvCalculations::FileToRows(string file)
{
	list<string> rows;

	ifstream fileStream (file.c_str());
	string line;

	if (fileStream.is_open())
	{
		while (getline(fileStream, line))
		{
			rows.push_back(line);
		}
		fileStream.close();
	}

	return rows;
}

//extracts the data column using the col header to find the index of the data in each row
list<double> csvCalculations::GetData(list<string> rows, string colHeader)
{
	list<double> data;

	string colHeaders = rows.front();
	rows.pop_front();

	string temp;
	int colIndex = -1;
	int i = 0;
	while (colHeaders.find(",", 0) != string::npos)
	{
		size_t  pos = colHeaders.find(",", 0);
		temp = colHeaders.substr(0, pos);
		colHeaders.erase(0, pos + 1);
		if(temp == colHeader)
		{
			colIndex = i;
		}
		i++;
	}

	if(colIndex != -1)
	{
		while(rows.size() > 0)
		{
			string row = rows.front();

			int j = 0;
			while (row.find(",", 0) != string::npos)
			{
				size_t  pos = row.find(",", 0);
				temp = row.substr(0, pos);
				row.erase(0, pos + 1);

				if(j == colIndex)
				{
					data.push_back(atof(temp.c_str()));
				}

				j++;
			}
			rows.pop_front();
		}
	}
	

	return data;
}

//returns a list of files for a given folder
list<string> csvCalculations::GetFiles(string folder)
{
	list<string> files;

	if(!fs::exists(folder))
	{
		return files;
	}

	if(fs::is_directory(folder))
	{
		fs::recursive_directory_iterator it(folder);
		fs::recursive_directory_iterator endit;

		while(it!= endit)
		{
			if (fs::is_regular_file(*it) && it->path().extension() == ".csv")
			{
				files.push_back(it->path().filename().string());
			}
			++it;
		}
	}

	files.sort();

	return files;
}

//counts the frequencies of a given column for all files
hash_map<string, hash_map<double, int>> csvCalculations::CalculateFrequenciesForFolder(string folder, string column)
{
	hash_map<string, hash_map<double, int>> results;

	stringstream ss;
	ss << folder << "\\";
	folder = ss.str();

	list<string> files = GetFiles(folder);

	for(list<string>::iterator it = files.begin(); it!=files.end(); it++)
	{
		stringstream ssf;
		string file = *it;
		ssf << folder << file;
		double result = 0.0;

		results[file] = CalculateFrequenciesForFile(ssf.str(), column);
	}

	return results;
}

//counts the frequencies of a given column for a given file
hash_map<double, int> csvCalculations::CalculateFrequenciesForFile(string file, string colHeader)
{
	hash_map<double, int> frequencies;
	list<double> data = GetData(FileToRows(file), colHeader);

	double total = 0;
	int count = 0;
	for(list<double>::iterator it = data.begin(); it != data.end(); it++)
	{
		double tempD = *it;

		if(frequencies.find(tempD) == frequencies.end())
		{
			frequencies[tempD] = 1;
		}
		else
		{
			frequencies[tempD] = frequencies[tempD] + 1;
		}
				
	}

	return frequencies;
}

//Merges files together that have a similar name
void csvCalculations::MergeFilesInFolder(string inputFolder, int chars, string outputFolder)
{
	hash_map<string, list<string>> filesMap;

	list<string> files = GetFiles(inputFolder);

	for(list<string>::iterator it = files.begin(); it != files.end(); it++)
	{
		string tempFilename = *it;
		
		stringstream ssf;
		string file = *it;
		ssf << inputFolder << "\\" << file;

		tempFilename.erase(0,chars);

		list<string> rows = FileToRows(ssf.str());

		if(filesMap.find(tempFilename) != filesMap.end())
		{
			rows.pop_front();	
			for(list<string>::iterator its = rows.begin(); its != rows.end(); its++)
			{
				string temp = *its;
				filesMap[tempFilename].push_back(temp);
			}
		}	
		else
		{
			filesMap[tempFilename] = rows;
		}		
	}


	//Finally loop through hash map writing each file to output folder
	for(hash_map<string, list<string>>::iterator it = filesMap.begin(); it!= filesMap.end(); it++)
	{
		stringstream ssof;
		ssof << outputFolder << "\\" << it->first;

		ofstream outputFile;
		outputFile.open(ssof.str().c_str());

		list<string> outputRows = it->second;

		for(list<string>::iterator ito = outputRows.begin(); ito != outputRows.end(); ito++)
		{
			outputFile << *ito << endl;
		}

		outputFile.close();
	}

}